#include "Network/ConnectionManager.h"
#include "Network/PackageManager.h"
#include "Network/BanManager.h"
#include "Network/ModsManager.h"
#include "Network/ServerRoot.h"
#include "Network/Packages/ClientPackage.h"
#include "Network/FastPackages/ConnectionRejectPackage.h"
#include "Network/FastPackages/ConnectionRequestPackage.h"

#include "Log.h"
#include "ServerConfigure.h"
#include "GameSingleton.h"

#include "Utils/Utils.h"

#include "LiteNetLib/NetUtils.h"
#include "Managers/GameManager.h"




namespace PocketSurvival
{
    ConnectionManager::ConnectionManager() : m_waitTime(0) {}

    bool ConnectionManager::handleNewRequest(ConnectionRequestPackage *connectionPackage, std::string &rejectMessage)
    {
        // 提取地址里面的ip，没有包含端口
        std::string ipStr = NetUtils::GetSockIP(&(connectionPackage->endpoint));

        if(GameSingleton::banManager->ipIsInBanSet(ipStr) == true || GameSingleton::banManager->guidIsInBanSet(connectionPackage->userGuid) == true)
        {
            rejectMessage = "time out ...";
            return false;
        }

        std::string address = NetUtils::GetAddressStr(&(connectionPackage->endpoint));
        Log::Info(fmt::format("收到 {} 请求连接 uuid:{} version:{} password:{} ", address, connectionPackage->userGuid.toString(), connectionPackage->version, connectionPackage->password));
        
        //  mod检测
        if(GameSingleton::modsManager->verifyMods(connectionPackage->modInfos) == false)
        {
            rejectMessage = "Mod验证不通过。请去掉多余的mod或添加服务器所需要的mod";
            return false;
        }

        // 密码检测，密码不正确将拒绝进入的请求
        if (GameSingleton::serverConfigure->password != "" && connectionPackage->password != GameSingleton::serverConfigure->password)
        {
            rejectMessage = "服务器密码错误";
            return false;
        }

        // 判断Guid对应的客户端是否在服务器中，如果是则会拒绝改连接
        ClientPtr inServerClient = GameSingleton::serverRoot->findClientByGuid(connectionPackage->userGuid);
        if(inServerClient != nullptr)
        {
            rejectMessage = "重复连接";
            Log::Warn(fmt::format("{} 尝试登录已经在线的玩家 {}", address, connectionPackage->userGuid.toString()), Log::LogType::NET);
            return false;                
        }

        // 判断玩家数量是否满了，满了的话就不能进入了
        if (GameSingleton::serverRoot->getClientCount() >= GameSingleton::serverConfigure->maxPlayer)
        {
            rejectMessage = "玩家数量已经满了,请稍后再试";
            Log::Info(fmt::format("当前玩家数量已经满了，已经拒绝了 {} 的连接请求", address), Log::LogType::NET);
            return false;
        }


        switch (GameSingleton::serverConfigure->loginType)
        {
        case LoginType::NeedCommunity:
            {
                /*
                std::string url = fmt::format("https://m.schub.top/com/checkuser?token={}&ip={}",Utils::StringReplace(connectionPackage->userGuid.toString(), "-", ""), address);
                ConnectionRequest *request = connectionPackage->request;
                GameGuid gameGuid = connectionPackage->userGuid;
                
                HttpRequestPtr req(new HttpRequest);
                req->method = HTTP_POST;
                req->url = url;
                req->headers["Connection"] = "keep-alive";
                req->timeout = 10;
                req->body = "";
                http_client_send_async(req, [request, gameGuid, url, this](const HttpResponsePtr &resp)
                {
                    std::string errorMess = "";
                    if (resp != NULL)
                    {
                        Log::Info(fmt::format("http post: {} ,body : {}", url, resp->body.c_str()), Log::LogType::NET);

                        try
                        {
                            nlohmann::json jsonData = nlohmann::json::parse(resp->body.c_str());
                            if(jsonData["code"].get<int32_t>() == 200)
                            {
                                std::string nickname = jsonData["data"]["nickname"].get<std::string>();
                                if(nickname.find(" ") != std::string::npos)
                                {
                                    errorMess = "名字包含特殊字符";
                                }
                                else
                                {
                                    NetPeerPtr netPeer = request->accept();
                                    if (netPeer != nullptr)
                                    {
                                        ClientPtr client = GameSingleton::serverRoot->findClientByAddrHash(netPeer->getHashCode());
                                        if (client == nullptr)
                                        {
                                            client = GameSingleton::serverRoot->createClient(netPeer, gameGuid, nickname);
                                            client->communityId = std::to_string(jsonData["data"]["id"].get<int32_t>());
                                            client->state = ClientState::Connected;
                                            addSyncGuid(client);
                                        }
                                    }
                                    return;
                                }
                            }
                            else
                            {
                                errorMess = "请先确保社区账号正常";
                            }
                        }
                        catch(const std::exception& e)
                        {
                            errorMess = fmt::format("社区数据错误");
                            Log::Error(fmt::format("社区数据错误: {}, {} 的连接失败", e.what(), NetUtils::GetAddressStr(&(request->endpoint))), Log::LogType::NET);
                        }
                    }
                    else
                    {
                        errorMess = "向社区请求数据出错";
                        Log::Error(errorMess, Log::LogType::NET);
                    }
                    std::shared_ptr<ConnectionRejectPackage> rejectPackage = std::make_shared<ConnectionRejectPackage>(&(request->endpoint));
                    rejectPackage->rejectReason = errorMess;
                    GameSingleton::packageManager->sendFastPackage(rejectPackage);
                    request->reject();
                });
                */
               rejectMessage = "社区功能未完善";
                return false;
            }
            break;
        case LoginType::CommunityLocal:
        case LoginType::Local:
            {
                std::string filePath = fmt::format("{}/{}.json", GameSingleton::gameManager->getNowWorldPlayersPath(), connectionPackage->userGuid.toString());
                if(std::filesystem::exists(filePath))
                {
                    ClientPtr client = GameSingleton::serverRoot->createClient(connectionPackage->request->accept(), connectionPackage->userGuid, "");
                    client->nickname = "";
                    client->communityId = "";

                    if (GameSingleton::serverConfigure->use0304)
                    {
                        client->tokenId = connectionPackage->token;
                    }
                    
                    client->state = ClientState::Connected;
                    syncGuidList(client);
                    return true;
                }
                rejectMessage = "新玩家无法进入";
                return false;
            }
            break;
        case LoginType::UnLimit:
            {
                // ClientPtr client = m_serverRoot->createClient(connectionPackage->request->accept(), , "");
                // if (client == nullptr)
                // {
                //     return true;
                // }
                // client->communityId = "";
                // client->state = ClientState::Connected;
                // addSyncGuid(client);

                NetPeerPtr netPeer = connectionPackage->request->accept();
                if (netPeer != nullptr)
                {
                    ClientPtr client = GameSingleton::serverRoot->findClientByAddrHash(netPeer->getHashCode());
                    if (client == nullptr)
                    {
                        client = GameSingleton::serverRoot->createClient(netPeer, connectionPackage->userGuid, "");
                        client->communityId = "";
                        
                        if (GameSingleton::serverConfigure->use0304)
                        {
                            client->tokenId = connectionPackage->token;
                            Log::Info(fmt::format("user: {}, guid: {}, token: {}", connectionPackage->username, connectionPackage->userGuid.toString(), connectionPackage->token.toString()));
                        }
                        else
                        {
                            Log::Info(fmt::format("user: {}, guid: {}", connectionPackage->username, connectionPackage->userGuid.toString()));
                        }

                        client->state = ClientState::Connected;
                        addSyncGuid(client);
                    }
                }
                return true;
            }
            break;
        }
        // 这里应该是到不了的

        rejectMessage = "服务器无法进入";
        Log::Error("ConnectionManager 发生严重错误");
        return false;
    }


    void ConnectionManager::syncGuidList(ClientPtr &client)
    {
        std::shared_ptr<ClientPackage> clientPackage = std::make_shared<ClientPackage>();
        clientPackage->dataType = ClientPackageType::SyncList;
        clientPackage->sendType = PackageSendType::TARGET;
        clientPackage->client = client;
        GameSingleton::serverRoot->getAllClients(clientPackage->syncListClient);
        GameSingleton::packageManager->sendPackage(clientPackage);

        // 告诉其它以连接上的客户端，有新的客户端连接
        std::shared_ptr<ClientPackage> addClientPackage = std::make_shared<ClientPackage>(client, ClientPackageType::Add);
        addClientPackage->sendType = PackageSendType::EXCEPT;
        addClientPackage->client = client;
        GameSingleton::packageManager->sendPackage(addClientPackage);
        Log::Info(fmt::format("玩家 [{}]{} 连接进服务器, 社区ID:{}", client->getAddress(), client->nickname, client->communityId));
    }


    void ConnectionManager::update(float dt)
    {
        // // 同步连接客户端的guid列表，一帧只同步一个玩家，防止多线程的同步错误

        ClientPtr client;
        if (m_waitSyncGuidQueue.try_dequeue(client))
        {
            syncGuidList(client);
        }
    }

    void ConnectionManager::load() {}
    void ConnectionManager::save() {}

} // namespace PocketSurvival
